﻿/*
Copyright (c) 2009, Luke Berndt
All rights reserved.
 
 * More Information: http://www.tagflo.com

Redistribution and use in source and binary forms, with or without modification, are permitted 
provided that the following conditions are met:

* Redistributions of source code must retain the above copyright notice, this list of conditions 
  and the following disclaimer.

* Redistributions in binary form must reproduce the above copyright notice, this list of conditions 
  and the following disclaimer in the documentation and/or other materials provided with the distribution.

* Neither the name of RoboTastic Software nor the names of its contributors may be used to endorse or 
  promote products derived from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED 
WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A 
PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR 
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED 
TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 
POSSIBILITY OF SUCH DAMAGE.
*/


using System;
using System.Data.SqlServerCe;
using System.Data.OleDb;
using System.Data.SqlClient;
using System.Data;
using System.Collections.Generic;
using System.Collections.ObjectModel;

using System.Linq;
using System.Text;
using System.IO;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.ComponentModel;
using System.Reflection;
using Bindable;
using Bindable.Linq;

namespace TagFlo.Views
{

    public class YearGroup : INotifyPropertyChanged
    {
        string year;
        IEnumerable<MonthGroup> monthGroups;
        public string Year {
            get
            {
                return year;
            }
            set
            {
                year = value;
                NotifyChanged("Year");
            }
        }
        public IEnumerable<MonthGroup> MonthGroups
        {
            get
            {
                return monthGroups;
            }
            set
            {
                monthGroups = value;
                NotifyChanged("MonthGroups");
            }
        }

        private void NotifyChanged(string propName)
        {
            if (PropertyChanged != null)
                PropertyChanged(this, new PropertyChangedEventArgs(propName));
        }

        public event PropertyChangedEventHandler PropertyChanged;
    }

    public class MonthGroup : INotifyPropertyChanged
    {
        public int MonthNum { get; set; }
        public string Month { get; set; }
        public string Year { get; set; }
        public IEnumerable<String> Dates { get; set; }
        private void NotifyChanged(string propName)
        {
            if (PropertyChanged != null)
                PropertyChanged(this, new PropertyChangedEventArgs(propName));
        }

        public event PropertyChangedEventHandler PropertyChanged;
    }

   

    /// <summary>
    /// Interaction logic for UserControl1.xaml
    /// </summary>
    public partial class SelectionPanel : TreeView
    {
        ThreadedObservableCollection<Photo> photoCollection;
        ThreadedObservableCollection<Path> pathCollection;
        ThreadedObservableCollection<Tag> tagCollection;
        ThreadedObservableCollection<PhotoSet> photoSetCollection;
        ThreadedObservableCollection<SmartSet> smartSetCollection;


        PhotoDBEntities photoEntities;// = new PhotoDBEntities();


        

        #region Filters Property
        public static readonly DependencyProperty FiltersProperty = DependencyProperty.Register("Filters",
            typeof(Collection<FilterSetting>),
            typeof(SelectionPanel),
            new PropertyMetadata(null, new PropertyChangedCallback(OnFiltersChanged)));
        



        public static readonly RoutedEvent FiltersChangedEvent =
            EventManager.RegisterRoutedEvent("FiltersChanged",
                                            RoutingStrategy.Bubble,
                                            typeof(RoutedEventHandler),
                                            typeof(SelectionPanel));



        public event RoutedEventHandler FiltersChanged
        {
            add { AddHandler(FiltersChangedEvent, value); }
            remove { RemoveHandler(FiltersChangedEvent, value); }
        }
        
        private static void OnFiltersChanged(DependencyObject o, DependencyPropertyChangedEventArgs e)
        {
            SelectionPanel selectionPanel = o as SelectionPanel;

            if (selectionPanel != null)
                selectionPanel.OnFiltersChanged((Collection<FilterSetting>)e.OldValue, (Collection<FilterSetting>)e.NewValue);

        }
        protected virtual void OnFiltersChanged(Collection<FilterSetting> oldValue, Collection<FilterSetting> newValue)
        {
            this.RaiseEvent(new RoutedEventArgs(SelectionPanel.FiltersChangedEvent, this));

        }
        

        private void RaiseFilterChangedEvent()
        {
            this.RaiseEvent(new RoutedEventArgs(SelectionPanel.FiltersChangedEvent, this));
        }

        public Collection<FilterSetting> Filters
        {

            // IMPORTANT: To maintain parity between setting a property in XAML
            // and procedural code, do not touch the getter and setter inside
            // this dependency property!

            get
            {
                return (Collection<FilterSetting>)GetValue(FiltersProperty);
            }

            set
            {
                SetValue(FiltersProperty, value);
            }
        }

        #endregion

        #region FiltersDescription Property
        public static readonly DependencyProperty FiltersDescriptionProperty = DependencyProperty.Register("FiltersDescription",
            typeof(String),
            typeof(SelectionPanel),
            new PropertyMetadata(null, new PropertyChangedCallback(OnFiltersDescriptionChanged)));




        public static readonly RoutedEvent FiltersDescriptionChangedEvent =
            EventManager.RegisterRoutedEvent("FiltersDescriptionChanged",
                                            RoutingStrategy.Bubble,
                                            typeof(RoutedEventHandler),
                                            typeof(SelectionPanel));



        public event RoutedEventHandler FiltersDescriptionChanged
        {
            add { AddHandler(FiltersChangedEvent, value); }
            remove { RemoveHandler(FiltersChangedEvent, value); }
        }

        private static void OnFiltersDescriptionChanged(DependencyObject o, DependencyPropertyChangedEventArgs e)
        {
            SelectionPanel selectionPanel = o as SelectionPanel;

            if (selectionPanel != null)
                selectionPanel.OnFiltersDescriptionChanged((String)e.OldValue, (String)e.NewValue);

        }
        protected virtual void OnFiltersDescriptionChanged(String oldValue, String newValue)
        {
            this.RaiseEvent(new RoutedEventArgs(SelectionPanel.FiltersDescriptionChangedEvent, this));

        }


        private void RaiseFilterDescriptionChangedEvent()
        {
            this.RaiseEvent(new RoutedEventArgs(SelectionPanel.FiltersDescriptionChangedEvent, this));
        }

        public String FiltersDescription
        {

            // IMPORTANT: To maintain parity between setting a property in XAML
            // and procedural code, do not touch the getter and setter inside
            // this dependency property!

            get
            {
                return (String)GetValue(FiltersDescriptionProperty);
            }

            set
            {
                SetValue(FiltersDescriptionProperty, value);
            }
        }
        #endregion

       
        private ImageSource LoadIcon(Type typ, string icon)
        {
            Assembly asm = Assembly.GetAssembly(typ);
            string iconString = typ.Namespace + '.' + icon.Replace('\\', '.');
            Stream myStream = asm.GetManifestResourceStream(iconString);

            if (myStream == null)
            {
                iconString = typ.Name + '.' + icon.Replace('\\', '.');
                myStream = asm.GetManifestResourceStream(iconString);
            }

        
            if (myStream != null)
            {
                PngBitmapDecoder bitmapDecoder = new PngBitmapDecoder(myStream, BitmapCreateOptions.PreservePixelFormat, BitmapCacheOption.Default);
                if (bitmapDecoder.Frames[0] != null && bitmapDecoder.Frames[0] is ImageSource)
                {
                    return bitmapDecoder.Frames[0];
                }
                else
                {
                    return null;
                }
            }
            return null;
        }
        public SelectionPanel()
        {
            InitializeComponent();
        }


       

        public void SelectTreeView_Update()
        {
            foreach (object i in this.Items)
            {
                Type t = i.GetType();
                if (t == typeof(SelectionPanelItem))
                {
                    SelectionPanelItem item = (SelectionPanelItem)i;
                    switch (item.HeaderText)
                    {
                        case "ISO":
                         
            item.ItemsSource = (from p in photoCollection select (p.IsoSpeed.ToString())).Distinct();
            break;
                        case "Exposure Time":
            item.ItemsSource = (from p in photoCollection.AsBindable() select (p.ExposureTime.ToString())).Distinct();
            break;
                        case "Focal Length":
            item.ItemsSource = (from p in photoCollection.AsBindable() select (p.FocalLength.ToString())).Distinct();
            break;

                        case "Lens Aperture":
            item.ItemsSource = (from p in photoCollection.AsBindable() select (p.LensAperture.ToString())).Distinct();
            break;
                        case "Camera Model":
            item.ItemsSource = (from p in photoCollection.AsBindable() select (p.CameraModel)).Distinct();
            break;

                        case "Rating":
            item.ItemsSource = new List<string> { "0", "1", "2", "3", "4", "5" }; //(from p in photoCollection select (p.Rating.ToString())).Distinct() 
            break;

                        case "Tag":
            item.ItemsSource = (from tag in tagCollection.AsBindable() select tag.TagName).Distinct();
            break;

                    }
                }
            }
          }

        public void PhotoSetItem_Update()
        {
            foreach (object item in this.Items)
            {
                Type t = item.GetType();
                if (t == typeof(SelectionPanelItem))
                {
                    SelectionPanelItem panelItem = (item as SelectionPanelItem);
                    if (panelItem.HeaderText == "Photo Sets")
                    {
                        panelItem.ItemsSource = (from ps in photoEntities.PhotoSets select (ps.PhotoSetName)).Distinct();
                    }
                }
             
            }
        }

        public void SmartSetItem_Update()
        {
            //photoEntities.Refresh(System.Data.Objects.RefreshMode.StoreWins,photoEntities.SmartSets.Include("SmartSetFilters"));
        
            foreach (object item in this.Items)
            {
                Type t = item.GetType();
                if (t == typeof(SelectionPanelItem))
                {
                    SelectionPanelItem panelItem = (item as SelectionPanelItem);
                    if (panelItem.HeaderText == "Smart Sets")
                    {
                        panelItem.ItemsSource = (from s in photoEntities.SmartSets select (s.SmartSetName)).Distinct();
                
                    }

                }

            }
        }

        public void SelectTreeView_Build( MainWindow mainWindow)
        {
          
            photoCollection = mainWindow.photoCollection;
            pathCollection = mainWindow.pathCollection;
            tagCollection = mainWindow.tagCollection;
            photoSetCollection = mainWindow.photoSetCollection;
            smartSetCollection = mainWindow.smartSetCollection;
            photoEntities = mainWindow.photoEntities;
            Uri iconUri;

            iconUri = new Uri(@"pack://application:,,,/Icons/picture.png", UriKind.Absolute);
            SelectionPanelItem item = new SelectionPanelItem("ISO", iconUri);
            item.AddHandler(TreeViewItem.SelectedEvent, new RoutedEventHandler(SelectionPanelItemSelected));
            item.ItemsSource = (from p in photoCollection.OrderBy(p=>p.IsoSpeed) select p.IsoSpeed.ToString()).Distinct();
            item.ItemTemplate = (DataTemplate) this.Resources["IsoSpeedTemplate"];
            
            this.Items.Add(item);

            item = new SelectionPanelItem("Exposure Time", iconUri);
            item.AddHandler(TreeViewItem.SelectedEvent, new RoutedEventHandler(SelectionPanelItemSelected));
            item.ItemsSource = (from p in photoCollection.OrderBy(p=>p.ExposureTime).AsBindable() select (p.ExposureTime.ToString())).Distinct();
            item.ItemTemplate = (DataTemplate)this.Resources["ExposureTimeTemplate"];
            
            this.Items.Add(item);

            item = new SelectionPanelItem("Focal Length", iconUri);
            item.AddHandler(TreeViewItem.SelectedEvent, new RoutedEventHandler(SelectionPanelItemSelected));
            item.ItemsSource = (from p in photoCollection.OrderBy(p=>p.FocalLength).AsBindable() select (p.FocalLength.ToString())).Distinct();
            item.ItemTemplate = (DataTemplate)this.Resources["FocalLengthTemplate"];
            
            this.Items.Add(item);

            item = new SelectionPanelItem("Lens Aperture",iconUri);
            item.AddHandler(TreeViewItem.SelectedEvent, new RoutedEventHandler(SelectionPanelItemSelected));
            item.ItemsSource = (from p in photoCollection.OrderBy(p=>p.LensAperture).AsBindable() select (p.LensAperture.ToString())).Distinct();
            item.ItemTemplate = (DataTemplate)this.Resources["LensApertureTemplate"];
            this.Items.Add(item);

            iconUri = new Uri(@"pack://application:,,,/Icons/camera.png", UriKind.Absolute);
            item = new SelectionPanelItem("Camera Model", iconUri);
            item.AddHandler(TreeViewItem.SelectedEvent, new RoutedEventHandler(SelectionPanelItemSelected));
            item.ItemsSource = (from p in photoCollection.OrderBy(p=>p.CameraModel).AsBindable() select (p.CameraModel)).Distinct();
            item.ItemTemplate = (DataTemplate)this.Resources["CameraModelTemplate"];
            this.Items.Add(item);

            iconUri = new Uri(@"pack://application:,,,/Icons/star.png", UriKind.Absolute);
            item = new SelectionPanelItem("Rating", iconUri);
            item.AddHandler(TreeViewItem.SelectedEvent, new RoutedEventHandler(SelectionPanelItemSelected));
            item.ItemsSource = new List<string>{"0","1","2","3","4","5"}; //(from p in photoCollection select (p.Rating.ToString())).Distinct();
            item.ItemTemplate = (DataTemplate)this.Resources["RatingTemplate"];
            this.Items.Add(item);

            iconUri = new Uri(@"pack://application:,,,/Icons/tag_blue.png", UriKind.Absolute);
            item = new SelectionPanelItem("Tag", iconUri);
            item.AddHandler(TreeViewItem.SelectedEvent, new RoutedEventHandler(SelectionPanelItemSelected));
            item.ItemsSource = (from t in tagCollection.AsBindable() select t.TagName).Distinct();
            this.Items.Add(item);

            iconUri = new Uri(@"pack://application:,,,/Icons/folder_image.png", UriKind.Absolute);
            item = new SelectionPanelItem("Photo Sets", iconUri);
            item.AddHandler(TreeViewItem.SelectedEvent, new RoutedEventHandler(SelectionPanelItemSelected));
            item.ItemsSource = (from ps in photoEntities.PhotoSets select (ps.PhotoSetName)).Distinct();
            this.Items.Add(item);

            iconUri = new Uri(@"pack://application:,,,/Icons/folder_lightbulb.png", UriKind.Absolute);
            item = new SelectionPanelItem("Smart Sets", iconUri);
            item.AddHandler(TreeViewItem.SelectedEvent, new RoutedEventHandler(SmartSetSelected));
            item.ItemsSource = (from s in photoEntities.SmartSets select (s.SmartSetName)).Distinct();
            this.Items.Add(item);
            
            var paths = pathCollection.ToList().AsPathHierarchy();// (p => p.Parent);
            PathTreeViewItem.ItemsSource = paths;
            PathTreeViewItem.AddHandler(TreeViewItem.SelectedEvent, new RoutedEventHandler(PathSelected));


            List<MonthGroup> groupedMonths = (from p in photoCollection.ToList<Photo>()
                        group (p.DateTaken.Value.ToString("dd MMM yyyy")) by new { Year = p.DateTaken.Value.Year.ToString(), Month = p.DateTaken.Value.ToString("MMMM"), MonthNum = p.DateTaken.Value.Month} into gr
                        select  new MonthGroup() { Month = gr.Key.Month, Year = gr.Key.Year, MonthNum = gr.Key.MonthNum, Dates = gr.Distinct() }).ToList(); 
            
            List<YearGroup> GroupedYears = (from p in groupedMonths
                               group p by new { Year = p.Year } into gr
                               select new YearGroup() { Year = gr.Key.Year, MonthGroups = gr }).ToList();

            DateTreeViewItem.ItemsSource = GroupedYears;
            DateTreeViewItem.AddHandler(TreeViewItem.SelectedEvent, new RoutedEventHandler(DateItemSelected));
        }

        private void DateItemSelected(object sender, RoutedEventArgs e)
        {
            FilterSetting filter;
            Collection<FilterSetting> filters = new Collection<FilterSetting>();
               
            if (this.SelectedItem.GetType() == typeof(string))
            {
                string s = (string)this.SelectedItem;
                DateTime dateTime;
                DateTime.TryParse(s, out dateTime);
                
                filter = new FilterSetting("Day");
                filter.FilterValue = dateTime.Day.ToString();
                filter.FilterComparison = "is";
                filters.Add(filter);

                filter = new FilterSetting("Month");
                filter.FilterValue = dateTime.Month.ToString();
                filter.FilterComparison = "is";
                filters.Add(filter);

                filter = new FilterSetting("Year");
                filter.FilterValue = dateTime.Year.ToString();
                filter.FilterComparison = "is";
                filters.Add(filter);
                
                Filters = filters;
                FiltersDescription = "Date = " + this.SelectedItem;
            }
            if (this.SelectedItem.GetType() == typeof(MonthGroup))
            {
                MonthGroup monthGroup = (MonthGroup)this.SelectedItem;

                filter = new FilterSetting("Month");
                filter.FilterValue = monthGroup.MonthNum.ToString(); 
                filter.FilterComparison = "is";
                filters.Add(filter);

                filter = new FilterSetting("Year");
                filter.FilterValue = monthGroup.Year;
                filter.FilterComparison = "is";
                filters.Add(filter);

                Filters = filters;
                FiltersDescription = "Month = " + monthGroup.Month + ", " + monthGroup.Year;
        
            }

            if (this.SelectedItem.GetType() == typeof(YearGroup))
            {
                YearGroup yearGroup = (YearGroup)this.SelectedItem;
                filter = new FilterSetting("Year");
                filter.FilterValue = yearGroup.Year;
                filter.FilterComparison = "is";
                filters.Add(filter);

                Filters = filters;
                FiltersDescription = "Year = " + yearGroup.Year;
        
            }
        }

        private void AllPhotosSelected(object sender, RoutedEventArgs e)
        {
            Collection<FilterSetting> filters = new Collection<FilterSetting>();
            
            FiltersDescription = "All Photos";
            //Filters.Clear();
            Filters = filters;
        }
        private void SelectionPanelItemSelected(object sender, RoutedEventArgs e)
        {
            if (this.SelectedItem.GetType() == typeof(string))
            {
                SmartSetFilter f = new SmartSetFilter();

                FilterSetting filter;
                Collection<FilterSetting> filters = new Collection<FilterSetting>();
                SelectionPanelItem item = (SelectionPanelItem)sender;
                filter = new FilterSetting(item.HeaderText);

                filter.FilterValue = (string)this.SelectedItem;
                filter.FilterComparison = "is";
                filters.Add(filter);
                FiltersDescription = item.HeaderText + " = " + this.SelectedItem;
                Filters = filters;
            }
        }

        private string PathChild(HierarchyPath hPath)
        {
            string c = "";
            foreach (HierarchyPath cPath in hPath.Childs)
            {
                c = c + PathChild(cPath);

            }
            
                return c + "," + hPath.Path.PathID.ToString();
            
        }
        private void PathSelected(object sender, RoutedEventArgs e)
        {
            SmartSetFilter f = new SmartSetFilter();

            FilterSetting filter;
            Collection<FilterSetting> filters = new Collection<FilterSetting>();

            filter = new FilterSetting("Path");
            HierarchyPath hPath = (HierarchyPath)this.SelectedItem;
            filter.FilterValue =  PathChild(hPath).TrimStart(',');

            filter.FilterComparison = "in";
            filters.Add(filter);
            FiltersDescription = "Tag = " + hPath.Path.FullPath;

            Filters = filters;
        }


        private void TagSelected(object sender, RoutedEventArgs e)
        {
            SmartSetFilter f = new SmartSetFilter();

            FilterSetting filter;
            Collection<FilterSetting> filters = new Collection<FilterSetting>();

            filter = new FilterSetting("Tag");
            filter.FilterValue = (string)this.SelectedItem;
            filter.FilterComparison = "is";
            filters.Add(filter);
            FiltersDescription = "Tag = " + this.SelectedItem;
           
            Filters = filters;
        }

        private void SmartSetSelected(object sender, RoutedEventArgs e)
        {
            if (this.SelectedItem.GetType() == typeof(string))
            {
                SmartSetFilter f = new SmartSetFilter();
                string selectedFilter = (string)this.SelectedItem;
                FilterSetting filter;
                
                SmartSet smartSet = photoEntities.SmartSets.Include("SmartSetFilters").Where("it.SmartSetName = '" + selectedFilter + "'").First();
                Collection<FilterSetting> filters = new Collection<FilterSetting>();

                foreach (SmartSetFilter smartSetFilter in smartSet.SmartSetFilters)
                {
                    filter = new FilterSetting(smartSetFilter.FilterType);
                    filter.FilterValue = smartSetFilter.FilterValue;
                    filter.FilterComparison = smartSetFilter.ComparisonType;
                    filters.Add(filter);
              
                }


                FiltersDescription = "Smart Set = " + this.SelectedItem;

                Filters = filters;
            }
        }


    }
}
